package com.zhangx.study.demo.forkjoin.pool;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;

/**
 * @ClassName ComplexDemo
 * @Description TODO
 * @Author zhangx
 * @Date 2021/6/3 9:05
 **/
@Slf4j
public class ComplexDemo {

    private static class SumTask extends RecursiveTask<Long>{

        FkDao dao;
        int fromId;
        int toId;

        public SumTask(FkDao fkDao,int fromId,int toId){
            this.dao = fkDao;
            this.fromId = fromId;
            this.toId = toId;
        }

        /**
         * The main computation performed by this task.
         *
         * @return the result of the computation
         */
        @Override
        protected Long compute() {
            Long sum = 0L;
            if (toId - fromId < FkDao.THRESHOLD){
//                log.info("计算从{}到{}",fromId,toId);
//                这证明是最后一次
                return dao.sum(fromId,toId);
            }else {
                int mid = (fromId+toId)/2;
                SumTask lefTask = new SumTask(dao,fromId,mid);
//                log.info("生成任务{}到{}",fromId,mid);
                SumTask rightTask = new SumTask(dao,mid+1,toId);
//                log.info("生成任务{}到{}",mid+1,toId);
                invokeAll(lefTask,rightTask);
                return lefTask.join()+rightTask.join();
            }
        }
    }

    public void optimizeHandle(){
        FkDao fkDao = new FkDao();
        Integer min = fkDao.getMin();
        Integer max = fkDao.getMax();
        System.out.println(Runtime.getRuntime().availableProcessors());
        long s1 = System.currentTimeMillis();
        ForkJoinPool pool = new ForkJoinPool();
        SumTask task = new SumTask(fkDao,min,max);
        pool.invoke(task);
        long s2 = System.currentTimeMillis();
        log.info("计算耗时{}s,结果={}",(s2-s1)/1000.0,task.join());
    }

    /**
     * 普通处理方式
     */
    public void normalHandle(){
        FkDao fkDao = new FkDao();
        Integer min = fkDao.getMin();
        Integer max = fkDao.getMax();
        long s1 = System.currentTimeMillis();
        long sum = 0;
        int fromId = min;
        int toId = min + FkDao.THRESHOLD;
        int count = 0;
        while (toId < max){
            sum = fkDao.sum(fromId,toId);
            fromId = toId +1;
            toId += FkDao.THRESHOLD;
            count++;
        }
        int end = toId - FkDao.THRESHOLD;
        if (end < max){
            fromId = end + 1;
            sum += fkDao.sum(fromId,max);
            count++;
        }
        long s2 = System.currentTimeMillis();
        log.info("计算{}次耗时{}s,结果={}",count,(s2-s1)/1000.0,sum);
    }

    public static void main(String[] args) {
        ComplexDemo complexDemo = new ComplexDemo();
        complexDemo.normalHandle();
        complexDemo.optimizeHandle();
    }
}
